#!/bin/bash
###############################################################################
#       脚本名称: test_utils_yq.sh
#       功能描述: YAML数据处理工具(utils_yq.sh)单元测试
#       作者: 林再来
#       日期: 2025-10-15
#       版本: 1.0
#       功能:
#           1、测试工具层YAML数据处理的所有核心功能
#           2、验证数据读写、格式转换、查询等功能
#           3、确保工具层的独立性和纯粹性
###############################################################################

# 切换到脚本目录
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1

# 加载测试框架
source ../test_framework.sh

# 加载被测模块
source ../../../scripts/utils/utils_yq.sh

# 创建临时测试目录
TEST_DIR=$(create_test_dir)

###############################################################################
# 测试用例
###############################################################################

# 测试: yq工具初始化
test_utils_yq_init() {
    utils_yq_init 2>/dev/null
    assert_not_empty "$utils_yq_binary" "yq工具应该被初始化"
}

# 测试: YAML文件验证 - 有效文件
test_utils_yq_validate_valid() {
    local test_file="$TEST_DIR/valid.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: TestApp
  version: 1.0.0
database:
  host: localhost
  port: 3306
EOF
    
    utils_yq_validate "$test_file" 2>/dev/null
}

# 测试: YAML文件验证 - 无效文件
test_utils_yq_validate_invalid() {
    local test_file="$TEST_DIR/invalid.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: TestApp
    invalid indentation
  port: 8080
  invalid: [unclosed array
EOF
    
    if utils_yq_validate "$test_file" 2>/dev/null; then
        echo "✗ 无效YAML文件应该验证失败"
        return 1
    else
        echo "✓ 无效YAML文件正确验证失败"
        return 0
    fi
}

# 测试: 读取YAML值 - 字符串
test_utils_yq_read_string() {
    local test_file="$TEST_DIR/read_string.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: MyApp
  description: "This is a test application"
EOF
    
    local name=$(utils_yq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name"
    
    local desc=$(utils_yq_read "$test_file" ".app.description" 2>/dev/null)
    assert_equals "This is a test application" "$desc"
}

# 测试: 读取YAML值 - 数字和布尔值
test_utils_yq_read_types() {
    local test_file="$TEST_DIR/read_types.yaml"
    cat > "$test_file" << 'EOF'
app:
  port: 8080
  timeout: 30.5
  debug: true
  enabled: false
EOF
    
    local port=$(utils_yq_read "$test_file" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
    
    local timeout=$(utils_yq_read "$test_file" ".app.timeout" 2>/dev/null)
    assert_equals "30.5" "$timeout"
    
    local debug=$(utils_yq_read "$test_file" ".app.debug" 2>/dev/null)
    assert_equals "true" "$debug"
}

# 测试: 读取嵌套YAML值
test_utils_yq_read_nested() {
    local test_file="$TEST_DIR/read_nested.yaml"
    cat > "$test_file" << 'EOF'
app:
  database:
    mysql:
      host: localhost
      port: 3306
      credentials:
        username: root
        password: secret
EOF
    
    local host=$(utils_yq_read "$test_file" ".app.database.mysql.host" 2>/dev/null)
    assert_equals "localhost" "$host"
    
    local username=$(utils_yq_read "$test_file" ".app.database.mysql.credentials.username" 2>/dev/null)
    assert_equals "root" "$username"
}

# 测试: 写入YAML值 - 字符串
test_utils_yq_write_string() {
    local test_file="$TEST_DIR/write_string.yaml"
    echo "{}" > "$test_file"
    
    utils_yq_write "$test_file" ".app.name" "TestApp" "string" 2>/dev/null
    utils_yq_write "$test_file" ".app.env" "production" "string" 2>/dev/null
    
    local name=$(utils_yq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "TestApp" "$name"
    
    local env=$(utils_yq_read "$test_file" ".app.env" 2>/dev/null)
    assert_equals "production" "$env"
}

# 测试: 写入YAML值 - 数字和布尔值
test_utils_yq_write_types() {
    local test_file="$TEST_DIR/write_types.yaml"
    echo "{}" > "$test_file"
    
    utils_yq_write "$test_file" ".app.port" "8080" "number" 2>/dev/null
    utils_yq_write "$test_file" ".app.debug" "true" "boolean" 2>/dev/null
    utils_yq_write "$test_file" ".app.enabled" "false" "boolean" 2>/dev/null
    
    local port=$(utils_yq_read "$test_file" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
    
    local debug=$(utils_yq_read "$test_file" ".app.debug" 2>/dev/null)
    assert_equals "true" "$debug"
    
    local enabled=$(utils_yq_read "$test_file" ".app.enabled" 2>/dev/null)
    assert_equals "false" "$enabled"
}

# 测试: 写入嵌套YAML值
test_utils_yq_write_nested() {
    local test_file="$TEST_DIR/write_nested.yaml"
    echo "{}" > "$test_file"
    
    utils_yq_write "$test_file" ".app.database.host" "localhost" "string" 2>/dev/null
    utils_yq_write "$test_file" ".app.database.port" "3306" "number" 2>/dev/null
    
    local host=$(utils_yq_read "$test_file" ".app.database.host" 2>/dev/null)
    assert_equals "localhost" "$host"
    
    local port=$(utils_yq_read "$test_file" ".app.database.port" 2>/dev/null)
    assert_equals "3306" "$port"
}

# 测试: 删除YAML键
test_utils_yq_delete() {
    local test_file="$TEST_DIR/delete_test.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: MyApp
  version: 1.0.0
  temp: should_be_deleted
  debug: true
EOF
    
    utils_yq_delete "$test_file" ".app.temp" 2>/dev/null
    
    local temp=$(utils_yq_read "$test_file" ".app.temp" 2>/dev/null)
    assert_empty "$temp" "删除的键应该不存在"
    
    local name=$(utils_yq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name" "其他键应该保持不变"
    
    local debug=$(utils_yq_read "$test_file" ".app.debug" 2>/dev/null)
    assert_equals "true" "$debug"
}

# 测试: 合并YAML文件 - merge模式
test_utils_yq_merge_mode() {
    local target="$TEST_DIR/target_merge.yaml"
    local source="$TEST_DIR/source_merge.yaml"
    
    cat > "$target" << 'EOF'
app:
  name: TargetApp
  version: 1.0.0
  debug: true
EOF
    
    cat > "$source" << 'EOF'
app:
  name: SourceApp
  port: 8080
  timeout: 30
EOF
    
    utils_yq_merge "$target" "$source" "merge" 2>/dev/null
    
    local name=$(utils_yq_read "$target" ".app.name" 2>/dev/null)
    assert_equals "SourceApp" "$name" "merge模式source应该覆盖target"
    
    local version=$(utils_yq_read "$target" ".app.version" 2>/dev/null)
    assert_equals "1.0.0" "$version" "target独有的键应该保留"
    
    local port=$(utils_yq_read "$target" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port" "source的新键应该被添加"
}

# 测试: 合并YAML文件 - overwrite模式
test_utils_yq_merge_overwrite() {
    local target="$TEST_DIR/target_overwrite.yaml"
    local source="$TEST_DIR/source_overwrite.yaml"
    
    cat > "$target" << 'EOF'
app:
  name: TargetApp
  version: 1.0.0
EOF
    
    cat > "$source" << 'EOF'
app:
  port: 8080
EOF
    
    utils_yq_merge "$target" "$source" "overwrite" 2>/dev/null
    
    local port=$(utils_yq_read "$target" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
}

# 测试: 列出所有键
test_utils_yq_list_keys() {
    local test_file="$TEST_DIR/list_keys.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: MyApp
  version: 1.0.0
  port: 8080
  debug: true
EOF
    
    local keys=$(utils_yq_list_keys "$test_file" ".app" 2>/dev/null)
    
    assert_success grep -q "name" <<< "$keys"
    assert_success grep -q "version" <<< "$keys"
    assert_success grep -q "port" <<< "$keys"
}

# 测试: 格式化YAML文件
test_utils_yq_format() {
    local test_file="$TEST_DIR/format_test.yaml"
    cat > "$test_file" << 'EOF'
app:
   name:    MyApp
   version:  1.0.0
EOF
    
    utils_yq_format "$test_file" 2 2>/dev/null
    
    # 验证格式化后文件仍然有效
    utils_yq_validate "$test_file" 2>/dev/null
    assert_success "格式化后的文件应该有效"
    
    local name=$(utils_yq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name" "格式化不应改变数据"
}

# 测试: YAML转JSON
test_utils_yq_to_json() {
    local yaml_file="$TEST_DIR/to_json.yaml"
    local json_file="$TEST_DIR/to_json.json"
    
    cat > "$yaml_file" << 'EOF'
app:
  name: MyApp
  port: 8080
  debug: true
EOF
    
    utils_yq_to_json "$yaml_file" "$json_file" 2>/dev/null
    
    assert_file_exists "$json_file" "JSON文件应该被创建"
    
    # 验证JSON文件内容
    assert_success grep -q '"name"' "$json_file"
    assert_success grep -q '"port"' "$json_file"
}

# 测试: JSON转YAML
test_utils_yq_from_json() {
    local json_file="$TEST_DIR/from_json.json"
    local yaml_file="$TEST_DIR/from_json.yaml"
    
    cat > "$json_file" << 'EOF'
{
  "app": {
    "name": "MyApp",
    "port": 8080,
    "debug": true
  }
}
EOF
    
    utils_yq_from_json "$json_file" "$yaml_file" 2>/dev/null
    
    assert_file_exists "$yaml_file" "YAML文件应该被创建"
    
    local name=$(utils_yq_read "$yaml_file" ".app.name" 2>/dev/null)
    assert_equals "MyApp" "$name"
    
    local port=$(utils_yq_read "$yaml_file" ".app.port" 2>/dev/null)
    assert_equals "8080" "$port"
}

# 测试: yq查询功能
test_utils_yq_query() {
    local test_file="$TEST_DIR/query_test.yaml"
    cat > "$test_file" << 'EOF'
servers:
  - name: server1
    ip: 192.168.1.1
    active: true
  - name: server2
    ip: 192.168.1.2
    active: false
  - name: server3
    ip: 192.168.1.3
    active: true
EOF
    
    # 查询active的服务器
    local result=$(utils_yq_query "$test_file" '.servers[] | select(.active == true) | .name' 2>/dev/null)
    
    echo "$result" | grep -q "server1"
    assert_success "应该包含server1"
    
    echo "$result" | grep -q "server3"
    assert_success "应该包含server3"
    
    echo "$result" | grep -q "server2"
    ! assert_success "不应该包含server2"
}

# 测试: 备份和恢复机制
test_utils_yq_backup_restore() {
    local test_file="$TEST_DIR/backup_test.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: OriginalApp
EOF
    
    # 写入会创建备份
    utils_yq_write "$test_file" ".app.name" "NewApp" "string" 2>/dev/null
    
    # 验证备份被删除（成功写入后）
    local backup_count=$(ls -1 "$TEST_DIR"/backup_test.yaml.bak.* 2>/dev/null | wc -l)
    assert_equals "0" "$backup_count" "成功写入后备份应该被删除"
    
    local name=$(utils_yq_read "$test_file" ".app.name" 2>/dev/null)
    assert_equals "NewApp" "$name"
}

# 测试: 空值和null处理
test_utils_yq_null_handling() {
    local test_file="$TEST_DIR/null_test.yaml"
    cat > "$test_file" << 'EOF'
app:
  name: MyApp
  description: null
EOF
    
    local desc=$(utils_yq_read "$test_file" ".app.description" 2>/dev/null)
    assert_empty "$desc" "null值应该返回空字符串"
    
    local nonexist=$(utils_yq_read "$test_file" ".app.nonexistent" 2>/dev/null)
    assert_empty "$nonexist" "不存在的键应该返回空字符串"
}

###############################################################################
# 运行所有测试
###############################################################################

test_suite_start "工具层 - YAML数据处理工具 (utils_yq.sh)"

run_test "yq工具初始化" test_utils_yq_init
run_test "YAML文件验证 - 有效文件" test_utils_yq_validate_valid
run_test "YAML文件验证 - 无效文件" test_utils_yq_validate_invalid
run_test "读取YAML值 - 字符串" test_utils_yq_read_string
run_test "读取YAML值 - 数字和布尔值" test_utils_yq_read_types
run_test "读取嵌套YAML值" test_utils_yq_read_nested
run_test "写入YAML值 - 字符串" test_utils_yq_write_string
run_test "写入YAML值 - 数字和布尔值" test_utils_yq_write_types
run_test "写入嵌套YAML值" test_utils_yq_write_nested
run_test "删除YAML键" test_utils_yq_delete
run_test "合并YAML文件 - merge模式" test_utils_yq_merge_mode
run_test "合并YAML文件 - overwrite模式" test_utils_yq_merge_overwrite
run_test "列出所有键" test_utils_yq_list_keys
run_test "格式化YAML文件" test_utils_yq_format
run_test "YAML转JSON" test_utils_yq_to_json
run_test "JSON转YAML" test_utils_yq_from_json
run_test "yq查询功能" test_utils_yq_query
run_test "备份和恢复机制" test_utils_yq_backup_restore
run_test "空值和null处理" test_utils_yq_null_handling

test_suite_end

# 清理测试目录
cleanup_test_dir "$TEST_DIR"

# 显示测试结果
print_test_summary

# 返回测试结果
exit_with_test_result

